import json
import numpy as np
from openai import AsyncOpenAI
from typing import Dict, List, Optional, Tuple


class LLMService:
    """LLM服务，使用通义千问API"""

    def __init__(self, api_key: str, base_url: str, model: str):
        self.client = AsyncOpenAI(
            api_key=api_key,
            base_url=base_url
        )
        self.model = model
        self.embedding_model = "text-embedding-v3"  # 通义千问的embedding模型

    async def analyze_post(self, post_content: str) -> Dict:
        """
        分析帖子内容，提取关键信息

        返回:
        {
            "intent": "寻求技术建议",
            "topics": ["推荐系统", "LLM", "知识图谱"],
            "skill_gap": ["系统设计", "图数据库"],
            "sentiment": "positive",
            "is_question": true
        }
        """

        prompt = f"""
你是一个社交网络分析助手。请分析以下帖子内容，提取关键信息。

帖子内容：
{post_content}

请以JSON格式返回分析结果，包含以下字段：
1. intent: 用户意图（如：寻求技术建议、分享经验、提问、讨论等）
2. topics: 相关话题列表（提取3-5个关键技术话题）
3. skill_gap: 用户可能需要学习的技能（列表）
4. sentiment: 情感倾向（positive/neutral/negative）
5. is_question: 是否是问题（true/false）
6. domains: 涉及的学科领域（如：计算机科学、数据科学、数学等）

只返回JSON，不要其他内容。
"""

        try:
            response = await self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {"role": "system", "content": "你是一个专业的内容分析助手，擅长提取关键信息和理解用户意图。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
            )

            content = response.choices[0].message.content.strip()

            # 尝试解析JSON
            # 移除可能的markdown代码块标记
            if content.startswith("```json"):
                content = content[7:]
            if content.startswith("```"):
                content = content[3:]
            if content.endswith("```"):
                content = content[:-3]

            result = json.loads(content.strip())
            return result

        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {e}")
            # 返回默认结果
            return {
                "intent": "一般讨论",
                "topics": ["技术"],
                "skill_gap": [],
                "sentiment": "neutral",
                "is_question": False,
                "domains": ["计算机科学"]
            }

        except Exception as e:
            print(f"LLM调用错误: {e}")
            raise

    async def find_topic_relations(self, topic1: str, topic2: str) -> Dict:
        """
        查找两个话题之间的关系

        返回:
        {
            "relation": "相关性描述",
            "strength": 0.8,  # 0-1之间
            "explanation": "详细说明"
        }
        """

        prompt = f"""
分析以下两个技术话题之间的关系：

话题1: {topic1}
话题2: {topic2}

请以JSON格式返回：
1. relation: 关系类型（如：基础依赖、应用场景、相关技术、数学基础等）
2. strength: 关联强度（0-1之间的数字，0表示无关，1表示强相关）
3. explanation: 一句话解释为什么有这个关系

只返回JSON。
"""

        try:
            response = await self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {"role": "system", "content": "你是一个技术领域专家，擅长分析不同技术之间的关系。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.5,
            )

            content = response.choices[0].message.content.strip()

            # 移除markdown标记
            if content.startswith("```json"):
                content = content[7:]
            if content.startswith("```"):
                content = content[3:]
            if content.endswith("```"):
                content = content[:-3]

            result = json.loads(content.strip())
            return result

        except Exception as e:
            print(f"话题关系分析错误: {e}")
            return {
                "relation": "相关",
                "strength": 0.5,
                "explanation": "两个话题可能有一定关联"
            }

    async def explain_recommendation(self, path: List[str]) -> str:
        """
        解释推荐路径

        参数:
            path: 推荐路径节点列表

        返回:
            一句话解释
        """

        prompt = f"""
有一个推荐路径经过以下节点：
{' -> '.join(path)}

请用一句话（20字以内）解释这个推荐链条的逻辑，让用户理解为什么会有这个推荐。

只返回解释文字，不要其他内容。
"""

        try:
            response = await self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {"role": "system", "content": "你是一个推荐系统解释助手，擅长用简洁的语言解释推荐逻辑。"},
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
            )

            explanation = response.choices[0].message.content.strip()
            return explanation

        except Exception as e:
            print(f"推荐解释生成错误: {e}")
            return "基于知识图谱的关联推荐"

    async def get_embedding(self, text: str) -> list:
        """
        获取文本的embedding向量

        参数:
            text: 输入文本

        返回:
            embedding向量（list）
        """
        try:
            response = await self.client.embeddings.create(
                model=self.embedding_model,
                input=text
            )
            return response.data[0].embedding
        except Exception as e:
            print(f"Embedding生成错误: {e}")
            # 返回零向量作为fallback
            return [0.0] * 1024

    def cosine_similarity(self, vec1: list, vec2: list) -> float:
        """
        计算两个向量的余弦相似度

        参数:
            vec1, vec2: 两个向量

        返回:
            相似度（0-1之间）
        """
        import numpy as np

        v1 = np.array(vec1)
        v2 = np.array(vec2)

        norm1 = np.linalg.norm(v1)
        norm2 = np.linalg.norm(v2)

        if norm1 == 0 or norm2 == 0:
            return 0.0

        return float(np.dot(v1, v2) / (norm1 * norm2))
